#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import requests
import json
import time
import logging
from urllib.parse import quote
import xlwt

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('ncm_metadata.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)

class NCMMetadataExtractor:
    def __init__(self, music_dir, output_file=None):
        self.music_dir = music_dir
        self.output_file = output_file or 'ncm_metadata.xls'
        self.headers = {
            'accept': '*/*',
            'accept-language': 'zh-CN,zh;q=0.9',
            'priority': 'u=1, i',
            'sec-ch-ua': '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '"macOS"',
            'sec-fetch-dest': 'empty',
            'sec-fetch-mode': 'cors',
            'sec-fetch-site': 'same-site',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'
        }
        
    def find_ncm_files(self):
        """查找目录下所有.ncm文件"""
        ncm_files = []
        for root, dirs, files in os.walk(self.music_dir):
            for file in files:
                if file.endswith('.ncm'):
                    ncm_files.append(os.path.join(root, file))
        return ncm_files
    
    def extract_song_info(self, ncm_file_path):
        """从.ncm文件名提取歌曲信息"""
        # 获取文件名（不含扩展名）
        filename = os.path.basename(ncm_file_path)
        song_info = filename.replace('.ncm', '')
        
        # 尝试分离歌曲名和艺术家
        if ' - ' in song_info:
            parts = song_info.split(' - ')
            if len(parts) >= 2:
                song_name = parts[0].strip()
                artist = parts[1].strip()
                return song_name, artist, song_info
        
        # 如果无法分离，则将整个文件名作为歌曲名
        return song_info, '', song_info
    
    def search_song_metadata(self, song_name, artist=''):
        """调用API搜索歌曲元数据"""
        try:
            # 构造搜索关键词
            keyword = song_name
            if artist:
                keyword = f"{song_name} {artist}"
            
            # URL编码
            encoded_keyword = quote(keyword)
            search_url = f"https://api.qqmp3.vip/api/songs.php?type=search&keyword={encoded_keyword}"
            
            logging.info(f"搜索歌曲: {keyword}")
            
            # 发送请求
            response = requests.get(search_url, headers=self.headers, timeout=10)
            
            if response.status_code == 200:
                data = response.json()
                logging.info(f"搜索成功: {keyword}")
                return data
            else:
                logging.error(f"搜索失败: {keyword}, 状态码: {response.status_code}")
                return None
                
        except Exception as e:
            logging.error(f"搜索歌曲 {keyword} 时出错: {e}")
            return None
    
    def process_all_files(self):
        """处理所有.ncm文件"""
        ncm_files = self.find_ncm_files()
        logging.info(f"找到 {len(ncm_files)} 个.ncm文件")
        
        if not ncm_files:
            logging.info("没有找到.ncm文件")
            return []
            
        metadata_list = []
        
        for i, ncm_file in enumerate(ncm_files, 1):
            try:
                logging.info(f"进度: {i}/{len(ncm_files)}")
                
                # 从文件名提取歌曲信息
                song_name, artist, full_name = self.extract_song_info(ncm_file)
                logging.info(f"提取信息: 歌曲='{song_name}', 艺术家='{artist}'")
                
                # 搜索元数据
                metadata = self.search_song_metadata(song_name, artist)
                
                if metadata:
                    # 添加文件路径信息
                    metadata['file_path'] = ncm_file
                    metadata['extracted_song_name'] = song_name
                    metadata['extracted_artist'] = artist
                    metadata_list.append(metadata)
                    logging.info(f"成功获取元数据: {song_name}")
                else:
                    # 即使没有找到元数据，也记录基本信息
                    metadata_list.append({
                        'file_path': ncm_file,
                        'extracted_song_name': song_name,
                        'extracted_artist': artist,
                        'search_result': None
                    })
                    logging.warning(f"未找到元数据: {song_name}")
                
                # 添加延迟避免请求过于频繁
                time.sleep(1)
                
            except Exception as e:
                logging.error(f"处理文件 {ncm_file} 时出错: {e}")
        
        logging.info(f"处理完成! 成功处理 {len(metadata_list)} 个文件")
        return metadata_list
    
    def save_to_excel(self, metadata_list):
        """将元数据保存到Excel文件"""
        if not metadata_list:
            logging.warning("没有数据可保存")
            return
            
        # 创建工作簿和工作表
        workbook = xlwt.Workbook(encoding='utf-8')
        worksheet = workbook.add_sheet('NCM Metadata')
        
        # 写入表头
        headers = ['文件路径', '提取的歌曲名', '提取的艺术家', '搜索结果']
        # 添加downurl列标题
        max_downurls = 0
        
        # 预处理数据，找出最大的downurl数量
        processed_data = []
        for metadata in metadata_list:
            row_data = {
                'file_path': metadata.get('file_path', ''),
                'extracted_song_name': metadata.get('extracted_song_name', ''),
                'extracted_artist': metadata.get('extracted_artist', ''),
                'search_result': metadata.get('search_result', metadata)
            }
            
            # 提取downurl
            downurls = []
            search_result = metadata.get('search_result', metadata)
            if search_result and isinstance(search_result, dict):
                data_list = search_result.get('data', [])
                if isinstance(data_list, list):
                    for item in data_list:
                        if isinstance(item, dict) and 'downurl' in item:
                            # 处理downurl数组
                            downurl_array = item['downurl']
                            if isinstance(downurl_array, list):
                                for url_item in downurl_array:
                                    if isinstance(url_item, str) and '$' in url_item:
                                        # 将"$$"替换为": "确保URL可以正常点击
                                        formatted_url = url_item.replace('$$', ': ')
                                        downurls.append(formatted_url)
            
            row_data['downurls'] = downurls
            max_downurls = max(max_downurls, len(downurls))
            processed_data.append(row_data)
        
        # 添加downurl列标题
        for i in range(max_downurls):
            headers.append(f'DownURL_{i+1}')
        
        # 写入表头
        for col, header in enumerate(headers):
            worksheet.write(0, col, header)
        
        # 写入数据
        for row, row_data in enumerate(processed_data, 1):
            worksheet.write(row, 0, row_data['file_path'])
            worksheet.write(row, 1, row_data['extracted_song_name'])
            worksheet.write(row, 2, row_data['extracted_artist'])
            worksheet.write(row, 3, json.dumps(row_data['search_result'], ensure_ascii=False))
            
            # 写入downurl
            for i, downurl in enumerate(row_data['downurls']):
                worksheet.write(row, 4 + i, downurl)
        
        # 保存文件
        workbook.save(self.output_file)
        logging.info(f"数据已保存到 {self.output_file}")

def main():
    import argparse
    
    # 解析命令行参数
    parser = argparse.ArgumentParser(description='提取.ncm文件元数据并保存到Excel')
    parser.add_argument('--music_dir', default='/Users/lijun/Library/Mobile Documents/com~apple~CloudDocs/Music', 
                       help='音乐文件目录')
    parser.add_argument('--output_file', default='ncm_metadata.xls', help='输出Excel文件路径')
    
    args = parser.parse_args()
    
    # 检查音乐目录是否存在
    if not os.path.exists(args.music_dir):
        logging.error(f"音乐目录不存在: {args.music_dir}")
        return
    
    # 创建提取器实例
    extractor = NCMMetadataExtractor(args.music_dir, args.output_file)
    
    # 处理所有文件
    metadata_list = extractor.process_all_files()
    
    # 保存到Excel
    extractor.save_to_excel(metadata_list)

if __name__ == "__main__":
    main()